/**
 * CompExaminationRooom.jsx
 * 1. 模板下载
 * 2. 使用说明
 * 3. 考场信息打印（已有）
 * 4. 准考证打印（新）
 * 5. 班级考号打印（新增）
 */
import React, { useState, useRef, useCallback } from 'react';
import { Upload, Button, message, Collapse, Card, Space, Checkbox, Select } from 'antd';
import { UploadOutlined, PrinterOutlined, DownloadOutlined } from '@ant-design/icons';
import * as XLSX from 'xlsx';
import { useReactToPrint } from 'react-to-print';

/* 工具：模糊匹配列名 */
const pickCol = (row, ...cands) => {
    for (const c of cands) {
        for (const k of Object.keys(row)) if (String(k).trim().includes(c)) return row[k];
    }
    return '';
};

/* 日期序列号 → yyyy-mm-dd */
const fmtDate = (raw) => {
    if (!raw) return '';
    if (!isNaN(raw)) {
        const epoch = new Date(1899, 11, 30);
        return new Date(epoch.getTime() + Number(raw) * 86400000).toISOString().slice(0, 10);
    }
    return String(raw);
};

/* 组件：按 5 条规则渲染考试时间表 */
const ExamSchedule = ({ list }) => {
    if (!list || !list.length) return null;

    const lines = [];          // 最终 JSX 行
    let prevDate = null;       // 上一行的日期
    let prevLineCount = 0;     // 上一行已放了几科

    list.forEach((item, idx) => {
        const { 日期, 科目, 时间 } = item;
        const isFirst = idx === 0;
        const dateChanged = 日期 !== prevDate;

        /* 规则 1 ：必须换行 */
        if (isFirst) {
            const txt = `时间：${日期} ${科目} ${时间}`.replace(/,+/g, '');
            lines.push(
                <div key={`line-${idx}`}>
                    {txt}
                </div>
            );
            prevLineCount = 1;
        }
        else {
            /* 规则4：日期不同 */
            if (dateChanged) {
                const txt = `${日期} ${科目} ${时间}`.replace(/,+/g, '');
                lines.push(
                    <div key={`line-${idx}`} style={{ marginLeft: 36 }}>
                        {txt}
                    </div>
                );
                prevLineCount = 1;
            }
            /* 日期相同 */
            else {
                /* 规则 2：上一行只有 1 科，本行追加 */
                if (prevLineCount === 1) {
                    const last = lines[lines.length - 1];
                    lines[lines.length - 1] = React.cloneElement(last, {
                        children: `${last.props.children}  ${科目} ${时间}`,
                    });
                    prevLineCount = 2;
                }
                /* 规则 3：上一行已有 2 科，换行 */
                else {
                    const txt = `${科目} ${时间}`.replace(/,+/g, '');
                    lines.push(
                        <div key={`line-${idx}`} style={{ marginLeft: 65 }}>
                            {txt}
                        </div>
                    );
                    prevLineCount = 1;
                }
            }
        }
        prevDate = 日期;
    });
    return <>{lines}</>;
};

const CompInfoPrintBeforeTest = () => {
    const [examData, setExamData] = useState({});
    const [subjectExamData, setSubjectExamData] = useState({}); // 存储各科考场数据
    const [params, setParams] = useState({ 考试名称: '', 考试时间: '', timeTable: [] });
    const printRef = useRef(null); // 考场用
    const admitRef = useRef(null); // 准考证用
    const classRef = useRef(null); // 班级考号用
    const [isInfoTechChecked, setIsInfoTechChecked] = useState(false);
    const [campus, setCampus] = useState('高一');//当前年级
    const [isSubjectSplit, setIsSubjectSplit] = useState(false); // 分科复选框状态
    const isMySeries = () => ['明远一', '明远二', '明远三'].includes(campus);
    const gradeLabel = (cl) => {
        if (isMySeries()) return `${campus}${cl}班`;
        return `${campus}${cl}班`;   // 高一/高二/高三
    };

    /* 1. 下载模板 */
    const downloadTpl = () => {
        try {
            const link = document.createElement('a');

            // 根据分科状态选择不同的模板文件
            const fileName = isSubjectSplit ? '考前准备(分科).xlsx' : '考前准备.xlsx';

            link.href = new URL(`/src/assets/${fileName}`, import.meta.url).href;
            link.download = fileName;
            link.click();
        } catch (error) {
            console.error('下载模板失败:', error);
            message.error('下载模板失败，请检查文件是否存在');
        }
    };

    /* 2. 上传解析 */
    const beforeUpload = useCallback((file) => {
        const reader = new FileReader();
        reader.onload = (e) => {
            try {
                const wb = XLSX.read(new Uint8Array(e.target.result), { type: 'array' });

                /* 参数表 */
                const ps = XLSX.utils.sheet_to_json(wb.Sheets['参数表'] || wb.Sheets[wb.SheetNames[1]] || wb.Sheets[wb.SheetNames[0]])[0] || {};

                /* ------ 新增：读"考试时间安排表" ------ */
                const timeSheet = wb.Sheets['考试时间安排表'] || wb.Sheets['时间安排表'];
                let timeTable = [];
                if (timeSheet) {
                    timeTable = XLSX.utils.sheet_to_json(timeSheet)
                        .map(r => ({
                            科目: pickCol(r, '科目').replace(/^,+|,+$/g, '').trim(),   // ← 去掉首尾逗号
                            日期: fmtDate(pickCol(r, '日期')),
                            时间: pickCol(r, '时间'),
                        }))
                        .filter(t => t.科目 && t.日期 && t.时间)
                        .sort((a, b) => (a.日期 + a.时间).localeCompare(b.日期 + b.时间));
                }

                setParams({
                    考试名称: pickCol(ps, '考试名称', '名称'),
                    考试时间: fmtDate(pickCol(ps, '考试时间', '时间')),
                    timeTable,               // ← 新增
                });

                /* 学生表 - 根据分科状态和年级类型选择不同的读取方式 */
                let grouped = {};
                let allSubjectData = {}; // 存储所有科目的原始数据

                if (!isSubjectSplit || isMySeries()) {
                    // 不分科或明远系列：读取考场学生信息表
                    const stus = XLSX.utils.sheet_to_json(wb.Sheets['考场学生信息表'] || wb.Sheets[wb.SheetNames[0]]);
                    stus.forEach((r) => {
                        const room = pickCol(r, '考场') || '未知考场';
                        if (!grouped[room]) grouped[room] = [];
                        grouped[room].push({
                            ...r,
                            座位号: Number(r.座位号 || 0),
                            智学号: pickCol(r, '智学号'),
                            考场类型: '语数外', // 默认考场类型
                        });
                    });
                } else {
                    // 分科且非明远系列：读取各科考场表
                    const subjectSheets = [
                        { name: '语数外考场', type: '语数外' },
                        { name: '物理考场', type: '物理' },
                        { name: '化学考场', type: '化学' },
                        { name: '生物考场', type: '生物' },
                        { name: '政治考场', type: '政治' },
                        { name: '历史考场', type: '历史' },
                        { name: '地理考场', type: '地理' }
                    ];

                    // 初始化各科数据存储
                    subjectSheets.forEach(({ type }) => {
                        allSubjectData[type] = {};
                    });

                    subjectSheets.forEach(({ name, type }) => {
                        const sheet = wb.Sheets[name];
                        if (sheet) {
                            const stus = XLSX.utils.sheet_to_json(sheet);
                            stus.forEach((r) => {
                                const room = pickCol(r, '考场') || `未知${type}考场`;
                                const roomKey = `${room}(${type})`; // 考场名加上类型
                                if (!grouped[roomKey]) grouped[roomKey] = [];

                                const studentData = {
                                    ...r,
                                    座位号: Number(r.座位号 || 0),
                                    智学号: pickCol(r, '智学号'),
                                    考场类型: type,
                                };

                                grouped[roomKey].push(studentData);

                                // 按学生存储各科考场信息
                                const studentKey = `${r.姓名}_${r.智学号}`;
                                if (!allSubjectData[type][studentKey]) {
                                    allSubjectData[type][studentKey] = studentData;
                                }
                            });
                        }
                    });

                    // 存储各科考场数据
                    setSubjectExamData(allSubjectData);
                }

                Object.keys(grouped).forEach((k) => grouped[k].sort((a, b) => a.座位号 - b.座位号));
                setExamData(grouped);
                message.success('解析成功');
            } catch (err) {
                message.error('解析失败：' + err.message);
            }
        };
        reader.readAsArrayBuffer(file);
        return false;
    }, [isSubjectSplit, campus]);

    /* 3. 考场打印 */
    const handlePrintRoom = useReactToPrint({
        contentRef: printRef,
        documentTitle: '考场信息',
        pageStyle: isMySeries()
            ? `@page { size: A4 portrait; margin: 20mm; } body { -webkit-print-color-adjust: exact; }`
            : `@page { size: A4 landscape; margin: 10mm; } body { -webkit-print-color-adjust: exact; }`,
    });

    /* 4. 准考证打印 */
    const handlePrintAdmit = useReactToPrint({
        contentRef: admitRef,
        documentTitle: '准考证',
        pageStyle: `@page { size: A4 portrait; margin: 3mm; } body { -webkit-print-color-adjust: exact; }`,
    });

    /* 5. 班级考号打印 */
    const handlePrintClass = useReactToPrint({
        contentRef: classRef,
        documentTitle: '班级考号',
        pageStyle: isMySeries()
            ? `@page { size: A4 portrait; margin: 20mm; } body { -webkit-print-color-adjust: exact; }`
            : `@page { size: A4 portrait; margin: 10mm; } body { -webkit-print-color-adjust: exact; }`,
    });

    /* 6. 考场块（明远系列：A4 纵向，2 班并排；普高系列：A4 横向，6 班并排） */
    const renderRoomBlocks = () => {
        const rooms = Object.keys(examData);
        const pages = [];

        const my = isMySeries();                 // 是否明远系列
        const perPage = my ? 2 : 6;              // 每页班数
        const direction = 'row';                 // 都用横向排列（明远 2 列，普高 6 列）

        // 分科模式下，按考场类型分组
        if (isSubjectSplit && !isMySeries()) {
            // 按考场类型分组
            const roomGroups = {};
            rooms.forEach(room => {
                // 从考场名中提取类型，如 "101(物理)" -> "物理"
                const match = room.match(/\((.*?)\)$/);
                const type = match ? match[1] : '语数外';
                if (!roomGroups[type]) roomGroups[type] = [];
                roomGroups[type].push(room);
            });

            // 按科目顺序排序
            const subjectOrder = ['语数外', '物理', '化学', '生物', '政治', '历史', '地理'];

            // 为每个科目类型创建页面
            subjectOrder.forEach((type, typeIndex) => {
                if (!roomGroups[type]) return;

                const typeRooms = roomGroups[type];
                const isLastType = typeIndex === subjectOrder.length - 1;

                // 每个科目类型内的考场分页
                for (let i = 0; i < typeRooms.length; i += perPage) {
                    const isLastPageInType = i + perPage >= typeRooms.length;
                    const isLastPageOverall = isLastType && isLastPageInType;

                    pages.push(
                        <div
                            key={`${type}-page-${i}`}
                            style={{
                                display: 'flex',
                                flexDirection: direction,
                                justifyContent: 'space-between',
                                gap: 4,
                                marginBottom: 20,
                                // 如果是该类型的最后一页，且不是最后一个类型，则换页
                                // 或者如果是该页的最后一组考场，则正常分页
                                pageBreakAfter: isLastPageOverall ? 'auto' : 'always',
                                fontSize: my ? '13pt' : '9pt',
                                lineHeight: 1.15,
                            }}
                        >
                            {Array.from({ length: perPage }).map((_, off) => {
                                const stus = examData[typeRooms[i + off]];
                                if (!stus) return <div style={{ width: `${100 / perPage}%` }} key={`empty-${off}`} />;

                                return (
                                    <div
                                        key={`room-${type}-${i + off}`}
                                        style={{
                                            width: `${100 / perPage}%`,
                                            padding: 4,
                                        }}
                                    >
                                        <div style={{ textAlign: 'center', fontWeight: 'bold', marginBottom: 3 }}>
                                            {typeRooms[i + off]}
                                        </div>
                                        <div style={{ textAlign: 'left', fontWeight: 'bold', marginBottom: 3 }}>
                                            座位号 姓名 班级 &nbsp;&nbsp;&nbsp;考试号
                                        </div>
                                        {stus.map((s) => (
                                            <div
                                                key={`${typeRooms[i + off]}-${s.座位号}`}
                                                style={{ display: 'flex', justifyContent: 'flex-start', gap: 6 }}
                                            >
                                                <span style={{
                                                    minWidth: 16,
                                                    width: '1em',
                                                    fontFamily: 'SimSun, monospace',
                                                    overflow: 'hidden',
                                                    whiteSpace: 'nowrap'
                                                }}>{s.座位号}</span>
                                                <span style={{
                                                    minWidth: 42,
                                                    width: '4em',
                                                    fontFamily: 'SimSun, monospace',
                                                    overflow: 'hidden',
                                                    whiteSpace: 'nowrap'
                                                }}>{s.姓名}</span>
                                                <span style={{
                                                    minWidth: 14,
                                                    width: '1em',
                                                    fontFamily: 'SimSun, monospace',
                                                    overflow: 'hidden',
                                                    whiteSpace: 'nowrap'
                                                }}>{s.班级}</span>
                                                <span>{s.智学号}</span>
                                            </div>
                                        ))}
                                    </div>
                                );
                            })}
                        </div>
                    );
                }
            });
        } else {
            // 原有逻辑（不分科或明远系列）
            for (let i = 0; i < rooms.length; i += perPage) {
                pages.push(
                    <div
                        key={`page-${i}`}
                        style={{
                            display: 'flex',
                            flexDirection: direction,
                            justifyContent: 'space-between',
                            gap: 4,
                            marginBottom: 20,
                            pageBreakAfter: i + perPage >= rooms.length ? 'auto' : 'always',
                            fontSize: my ? '13pt' : '9pt',
                            lineHeight: 1.15,
                        }}
                    >
                        {Array.from({ length: perPage }).map((_, off) => {
                            const stus = examData[rooms[i + off]];
                            if (!stus) return <div style={{ width: `${100 / perPage}%` }} key={`empty-${off}`} />;

                            return (
                                <div
                                    key={`room-${i + off}`}
                                    style={{
                                        width: `${100 / perPage}%`,   // 明远 50%，普高 16.67%
                                        padding: 4,
                                    }}
                                >
                                    <div style={{ textAlign: 'center', fontWeight: 'bold', marginBottom: 3 }}>
                                        {rooms[i + off]}
                                    </div>
                                    <div style={{ textAlign: 'left', fontWeight: 'bold', marginBottom: 3 }}>
                                        座位号 姓名 班级 &nbsp;&nbsp;&nbsp;考试号
                                    </div>
                                    {stus.map((s) => (
                                        <div
                                            key={`${rooms[i + off]}-${s.座位号}`}
                                            style={{ display: 'flex', justifyContent: 'flex-start', gap: 6 }}
                                        >
                                            <span style={{
                                                minWidth: 16,
                                                width: '1em',
                                                fontFamily: 'SimSun, monospace',
                                                overflow: 'hidden',
                                                whiteSpace: 'nowrap'
                                            }}>{s.座位号}</span>
                                            <span style={{
                                                minWidth: 42,
                                                width: '4em',
                                                fontFamily: 'SimSun, monospace',
                                                overflow: 'hidden',
                                                whiteSpace: 'nowrap'
                                            }}>{s.姓名}</span>
                                            <span style={{
                                                minWidth: 14,
                                                width: '1em',
                                                fontFamily: 'SimSun, monospace',
                                                overflow: 'hidden',
                                                whiteSpace: 'nowrap'
                                            }}>{s.班级}</span>
                                            <span>{s.智学号}</span>
                                        </div>
                                    ))}
                                </div>
                            );
                        })}
                    </div>
                );
            }
        }
        return pages;
    };

    /* 获取学生各科考场信息 */
    const getStudentSubjectInfo = (student) => {
        const studentKey = `${student.姓名}_${student.智学号}`;
        const subjectInfo = {};

        // 检查学生在各科考场中的信息
        const subjects = ['语数外', '物理', '化学', '生物', '政治', '历史', '地理'];
        subjects.forEach(subject => {
            if (subjectExamData[subject] && subjectExamData[subject][studentKey]) {
                subjectInfo[subject] = subjectExamData[subject][studentKey];
            }
        });

        return subjectInfo;
    };

    /* 准考证块（2×6=12 张/页）→ 按班级分页，班级内部继续每 12 张切页 */
    const renderAdmitCards = () => {
        // 分科且非明远系列时，需要重新读取语数外考场数据
        let all = [];

        if (isSubjectSplit && !isMySeries()) {
            // 使用语数外考场数据作为基础
            all = Object.values(examData)
                .flat()
                .filter(student => student.考场类型 === '语数外')
                .sort((a, b) => {
                    // 将班级转换为数字进行排序
                    const classA = parseInt(a.班级) || 0;
                    const classB = parseInt(b.班级) || 0;
                    return classA - classB;
                });
        } else {
            all = Object.values(examData)
                .flat()
                .sort((a, b) => {
                    // 将班级转换为数字进行排序
                    const classA = parseInt(a.班级) || 0;
                    const classB = parseInt(b.班级) || 0;
                    return classA - classB;
                });
        }

        const pages = [];
        let buffer = [];
        let prevClass = null;

        const flush = () => {
            if (!buffer.length) return;
            const rows = [];
            for (let r = 0; r < 6; r++) {
                const pair = [buffer[r * 2], buffer[r * 2 + 1]].filter(Boolean);
                rows.push(
                    <div key={`row-${pages.length}-${r}`} style={{ display: 'flex', gap: 40, marginBottom: 25 }}>
                        {pair.map((s, idx) => (
                            <div
                                key={`admit-${s.班级}-${s.座位号}-${idx}`}
                                style={{
                                    width: '45%',
                                    height: 140,
                                    border: '2px solid #000',
                                    padding: '8px 6px',
                                    display: 'flex',
                                    flexDirection: 'column',
                                    justifyContent: 'space-between',
                                    fontSize: 12,
                                    lineHeight: (isMySeries() ? 1.7 : isInfoTechChecked ? 1.1 : 1.3),
                                }}
                            >
                                <div style={{ fontSize: 14, fontWeight: 'bold', textAlign: 'center', marginBottom: 4 }}>
                                    {params.考试名称}考试证
                                </div>
                                <div style={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 2 }}>
                                    <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                                        <span>姓名：{s.姓名}</span>
                                        <span>班级：{s.班级}</span>
                                        <span>考试证号：{s.智学号}</span>
                                    </div>
                                    {/* 分科选中时不打印考场和座位号行 */}
                                    {!(isSubjectSplit && !isMySeries()) && (
                                        <div style={{ display: 'flex', justifyContent: 'space-between' }}>
                                            <span>考场：{pickCol(s, '考场')}</span>
                                            <span>座位号：{s.座位号}</span>
                                        </div>
                                    )}

                                    {/* 分科且非明远系列时的特殊显示 */}
                                    {isSubjectSplit && !isMySeries() ? (
                                        <div style={{ marginTop: 4 }}>
                                            {params.timeTable
                                                .filter(exam => {
                                                    // 过滤出学生实际参加的考试科目
                                                    const subjectInfo = getStudentSubjectInfo(s);
                                                    const examSubject = exam.科目;

                                                    // 映射科目名称
                                                    const subjectMap = {
                                                        '语文': '语数外',
                                                        '数学': '语数外',
                                                        '英语': '语数外',
                                                        '物理': '物理',
                                                        '化学': '化学',
                                                        '生物': '生物',
                                                        '政治': '政治',
                                                        '历史': '历史',
                                                        '地理': '地理',
                                                        '技术': '语数外' // 技术使用语数外考场
                                                    };

                                                    const subjectType = subjectMap[examSubject];
                                                    if (!subjectType) return false;

                                                    // 检查学生是否参加该科目考试
                                                    return !!subjectInfo[subjectType];
                                                })
                                                .map((exam, index) => {
                                                    const subjectInfo = getStudentSubjectInfo(s);
                                                    const examSubject = exam.科目;

                                                    // 映射科目名称
                                                    const subjectMap = {
                                                        '语文': '语数外',
                                                        '数学': '语数外',
                                                        '英语': '语数外',
                                                        '物理': '物理',
                                                        '化学': '化学',
                                                        '生物': '生物',
                                                        '政治': '政治',
                                                        '历史': '历史',
                                                        '地理': '地理',
                                                        '技术': '语数外'
                                                    };

                                                    const subjectType = subjectMap[examSubject];
                                                    const subjectData = subjectInfo[subjectType];

                                                    return (
                                                        // <div key={`exam-${index}`} style={{
                                                        //     fontSize: 12,
                                                        //     lineHeight: isInfoTechChecked ? 1.25 : 1.4,
                                                        //     display: 'grid',
                                                        //     gridTemplateColumns: '2.3fr 1.1fr 1.9fr 1fr',
                                                        //     gap: '3px',
                                                        //     alignItems: 'center'
                                                        // }}>
                                                        //     <span style={{whiteSpace: 'nowrap' }}>时间:{exam.日期}{exam.时间}</span>
                                                        //     <span style={{whiteSpace: 'nowrap' }}>科目:{exam.科目}</span>
                                                        //     <span style={{whiteSpace: 'nowrap' }}>考场:{subjectData?.考场 || s.考场}</span>
                                                        //     <span style={{whiteSpace: 'nowrap' }}>座位号:{subjectData?.座位号 || s.座位号}</span>
                                                        // </div>
                                                        <div key={`exam-${index}`} style={{
                                                            fontSize: 12,
                                                            lineHeight: isInfoTechChecked ? 1.25 : 1.4
                                                        }}>
                                                            <span style={{ display: 'inline-block', width: '37%', whiteSpace: 'nowrap' }}>
                                                                时间:{exam.日期}{exam.时间}
                                                            </span>
                                                            <span style={{ display: 'inline-block', width: '18%', whiteSpace: 'nowrap' }}>
                                                                科目:{exam.科目}
                                                            </span>
                                                            <span style={{ display: 'inline-block', width: '30%', whiteSpace: 'nowrap' }}>
                                                                考场:{subjectData?.考场 || s.考场}
                                                            </span>
                                                            <span style={{ display: 'inline-block', width: '15%', whiteSpace: 'nowrap' }}>
                                                                座位号:{subjectData?.座位号 || s.座位号}
                                                            </span>
                                                        </div>
                                                    );
                                                })}
                                        </div>
                                    ) : (
                                        <ExamSchedule list={params.timeTable} />
                                    )}
                                </div>
                            </div>
                        ))}
                        {pair.length === 1 && (
                            <div
                                style={{
                                    width: '45%',
                                    padding: '8px 6px',
                                    border: '2px solid transparent'
                                }}
                            />
                        )}
                    </div>
                );
            }
            pages.push(
                <div key={`page-${pages.length}`} style={{ pageBreakAfter: 'always' }}>
                    {rows}
                </div>
            );
            buffer = [];
        };

        all.forEach((stu) => {
            // 使用数字比较班级
            const currentClass = parseInt(stu.班级) || 0;
            if (prevClass !== null && currentClass !== prevClass) {
                flush();
            }
            buffer.push(stu);
            prevClass = currentClass;
            if (buffer.length === 12) flush();
        });
        flush();

        if (pages.length) {
            const last = pages[pages.length - 1];
            return pages.slice(0, -1).concat(
                React.cloneElement(last, { style: { pageBreakAfter: 'auto' } })
            );
        }
        return pages;
    };

    /* 班级考号块（每列70人，每页5个班级） */
    const renderClassBlocks = () => {
        /* 1. 统一排序 - 分科且非明远系列时只使用语数外考场数据 */
        let all = [];

        if (isSubjectSplit && !isMySeries()) {
            all = Object.values(examData)
                .flat()
                .filter(student => student.考场类型 === '语数外')
                .sort((a, b) => {
                    const cls = String(a.班级 || '').localeCompare(String(b.班级 || ''));
                    if (cls !== 0) return cls;
                    const room = String(pickCol(a, '考场') || '').localeCompare(String(pickCol(b, '考场') || ''));
                    if (room !== 0) return room;
                    return (a.座位号 || 0) - (b.座位号 || 0);
                });
        } else {
            all = Object.values(examData)
                .flat()
                .sort((a, b) => {
                    const cls = String(a.班级 || '').localeCompare(String(b.班级 || ''));
                    if (cls !== 0) return cls;
                    const room = String(pickCol(a, '考场') || '').localeCompare(String(pickCol(b, '考场') || ''));
                    if (room !== 0) return room;
                    return (a.座位号 || 0) - (b.座位号 || 0);
                });
        }

        /* 2. 按班级分组 */
        const byClass = {};
        all.forEach((s) => {
            const c = s.班级 || '未知班级';
            if (!byClass[c]) byClass[c] = [];
            byClass[c].push(s);
        });

        const pages = [];
        const cls = Object.keys(byClass);
        const my = isMySeries();          // 明远系列
        const perRow = my ? 2 : 6;        // 每行班数
        const colW = my ? '50%' : '19%';  // 列宽

        for (let i = 0; i < cls.length; i += perRow) {
            pages.push(
                <div
                    key={`cls-page-${i}`}
                    style={{
                        display: 'flex',
                        justifyContent: 'space-between',
                        gap: 8,
                        marginBottom: 16,
                        pageBreakAfter: i + perRow >= cls.length ? 'auto' : 'always',
                    }}
                >
                    {Array.from({ length: perRow }).map((_, off) => {
                        const cl = cls[i + off];
                        const stus = byClass[cl];
                        if (!stus) return <div style={{ width: colW }} key={`empty-${off}`} />;

                        /* 每班最多 70 人一排 */
                        const cols = [];
                        for (let c = 0; c < stus.length; c += 70) {
                            const col = stus.slice(c, c + 70);
                            cols.push(
                                <div
                                    key={`col-${cl}-${c}`}
                                    style={{
                                        display: 'flex',
                                        flexDirection: 'column',
                                        gap: 1,
                                        fontSize: my ? '13pt' : '9pt',
                                        lineHeight: 1.15,
                                    }}
                                >
                                    {c === 0 && (
                                        <div style={{ fontWeight: 'bold', marginBottom: 2, textAlign: 'center' }}>
                                            {gradeLabel(cl)}
                                        </div>
                                    )}
                                    {col.map((s, idx) => (
                                        <div key={`${cl}-${s.智学号}-${idx}`} style={{ display: 'flex', gap: 4 }}>
                                            <span
                                                style={{
                                                    display: 'inline-block',
                                                    width: '4em',
                                                    fontFamily: 'SimSun, monospace',
                                                    overflow: 'hidden',
                                                    whiteSpace: 'nowrap',
                                                }}
                                            >
                                                {s.姓名}
                                            </span>
                                            <span>{s.智学号}</span>
                                        </div>
                                    ))}
                                </div>
                            );
                        }
                        return (
                            <div
                                key={`cls-${cl}`}
                                style={{ width: colW, padding: 4, display: 'flex', gap: 4 }}
                            >
                                {cols}
                            </div>
                        );
                    })}
                </div>
            );
        }
        return pages;
    };

    /* 使用说明 */
    const usage = (
        <Collapse defaultActiveKey={['1']}
            items={[
                {
                    key: '1',
                    label: '📖 使用说明',
                    children: (
                        <Space direction="vertical" style={{ width: '100%' }}>
                            <Card size="small" title="① 下载模板">
                                点击"下载模板"按钮，获取标准 Excel 文件。
                            </Card>
                            <Card size="small" title="② 上传文件">
                                修改学生信息、考场信息、参数表、考试时间安排表，填写完成后，点击"上传 Excel"导入数据。
                            </Card>
                            <Card size="small" title="③ 打印考场信息">
                                点击"打印考场"即可按 A4 横向、每页 6 个考场输出，如果是明远班则是2个考场，打印方向也改为纵向。
                            </Card>
                            <Card size="small" title="④ 打印准考证">
                                点击"打印准考证"即可按 A4 纵向、每页 12 张（2×6）输出。
                            </Card>
                            <Card size="small" title="⑤ 打印班级考号">
                                点击"打印班级考号"即可按 A4 纵向、每页 6 个班级输出，如果是明远班则是2个班级。
                            </Card>
                            <Card size="small" title="⑥ 分科功能">
                                当选择"分科"且年级为高一/高二/高三时，系统会读取各科独立考场表，准考证会显示各科考试详情。
                            </Card>
                        </Space>
                    ),
                },
            ]}
        />
    );

    return (
        <div>
            {/* 操作区 */}
            <Space wrap style={{ marginBottom: 16 }}>
                <Checkbox
                    checked={isSubjectSplit}
                    onChange={(e) => setIsSubjectSplit(e.target.checked)}
                    style={{ marginRight: 8 }}
                >
                    分科
                </Checkbox>
                <Select value={campus} onChange={setCampus} style={{ width: 100 }}>
                    <Select.Option value="明远一">明远一</Select.Option>
                    <Select.Option value="明远二">明远二</Select.Option>
                    <Select.Option value="明远三">明远三</Select.Option>
                    <Select.Option value="高一">高一</Select.Option>
                    <Select.Option value="高二">高二</Select.Option>
                    <Select.Option value="高三">高三</Select.Option>
                </Select>
                <Button icon={<DownloadOutlined />} onClick={downloadTpl}>
                    下载模板
                </Button>
                <Upload accept=".xlsx" beforeUpload={beforeUpload} showUploadList={false}>
                    <Button icon={<UploadOutlined />}>上传 Excel</Button>
                </Upload>
                <Button icon={<PrinterOutlined />} onClick={handlePrintRoom} disabled={!Object.keys(examData).length}>
                    打印考场
                </Button>
                <Button icon={<PrinterOutlined />} onClick={handlePrintClass} disabled={!Object.keys(examData).length}>
                    打印班级考号
                </Button>
                <Button icon={<PrinterOutlined />} onClick={handlePrintAdmit} disabled={!Object.keys(examData).length}>
                    打印准考证
                </Button>
                <Checkbox
                    checked={isInfoTechChecked}
                    onChange={(e) => setIsInfoTechChecked(e.target.checked)}
                    style={{ marginLeft: 8 }}
                >
                    考信息技术
                </Checkbox>
            </Space>

            {/* 使用说明 */}
            {usage}

            {/* 打印区域 */}
            <div style={{ display: 'none' }}>
                <div ref={printRef}>{renderRoomBlocks()}</div>
                <div ref={admitRef}>{renderAdmitCards()}</div>
                <div ref={classRef}>{renderClassBlocks()}</div>
            </div>
        </div>
    );
};

export default CompInfoPrintBeforeTest;